package deduplication;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;

import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;

import java.io.Reader;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;

public class carnetContacts {
    
    File input;
    ArrayList<contact> carnet;
    HashMap<String,numeroTelephone> telephones;
    HashMap<String,adresseMail> emails;
    private String stringEncloser;
    private String separator;
    private String header;
    private int nbLines;
    private int nbTelephones;
    private int nbEmails;
    
    public carnetContacts() {
        super();
        nbLines=0;
        carnet = new ArrayList<contact>();
        telephones = new HashMap<String,numeroTelephone>();
        emails = new HashMap<String,adresseMail>();
    }

    public int size() {
        return carnet.size();
    }

    public int sizeTelephones() {
        return telephones.size();
    }

    public int sizeEmails() {
        return emails.size();
    }
    
    public Boolean load(File input) {
        if (this.input == null) {
            this.input = input;
            return load();
        }
        return false;
    }

    public Boolean load() {
        
        if (this.input == null) return false;
        
        Boolean result = false;
        BufferedReader in;

        try {
            in = new BufferedReader(new FileReader(this.input));
            if (!this.input.exists() || !this.input.canRead()) {
                System.err.println("File "+this.input + " can not be found or openned for read.");
                return false;
            } else {
                String line;
                String line2;
                try {
                    line2 = in.readLine();
                    this.nbLines=this.nbLines+1;
                    if (line2 == null) {
                        in.close();
                        return true;
                    }
                    this.stringEncloser="";
                    if (line2.charAt(0) == '\"') this.stringEncloser = "\"";
                    else if (line2.charAt(0)=='\'') this.stringEncloser="'";
                    else return false;
                    this.separator=line2.substring(line2.indexOf(stringEncloser, 2)+1, line2.indexOf(stringEncloser, 2)+2);
                    this.header=line2;
                    line2 = null;
                    do {
                        line=line2;
                        do {
                            line2=in.readLine();
                            this.nbLines=this.nbLines+1;
                            if (line2!=null) {
                                if (line2.startsWith(separator) || (line2.startsWith(stringEncloser) && !line2.startsWith(stringEncloser+separator))) {
                                    if (line!=null) break;
                                    line=line2;
                                } else {
                                    if (!line2.startsWith(stringEncloser+separator)) {
                                        line += " - " + line2;
                                    } else {
                                        line += line2;
                                    }
                                }
                                line2=null;
                            } else
                                break;
                        } while (true);
                        if (line != null) {
                            System.out.println(String.format("%05d", this.nbLines)+": "+line);
                            ArrayList<String> values=split(line,separator,stringEncloser);
                            contact c = new contact(values);
                            System.out.println(String.format("%05d", this.nbLines)+": "+c.toLine(separator, stringEncloser));
                            System.out.print("Contact "+c.getId()+" = "+c.getNom());
                            c.setId(carnet.size());
                            if (!carnet.add(c)) {
                                System.out.print(" pas ajouté !!!");
                            } else {
                                System.out.println(" ajouté en position "+c.getId()+".");
                            }
                        }
                    } while (line != null);
                    in.close();
                    System.out.println(this.input + " => "+this.nbLines+" lignes, "+carnet.size()+" contacts, "+nbTelephones+" téléphones, "+nbEmails+" emails.");
                    this.input = null;
                }
                catch (IOException e) {
                    System.err.println("Trying to read file " + this.input);
                    e.printStackTrace();
                    return false;
                }
            }
        } catch (FileNotFoundException e) {
            System.err.println("Trying to open file " + this.input);
            e.printStackTrace();
            return false;
        }
        return result;
    }

    public Boolean save(File outFile) {
        
        if (outFile == null) return false;
        if (this.input == null) this.input = outFile;

        Boolean result = false;
        BufferedWriter out;

        try {
            out = new BufferedWriter(new FileWriter(this.input));
            if (!this.input.exists() || !this.input.canWrite() ) {
                System.err.println("File "+this.input + " can not be found or openned for write.");
                return false;
            } else {
                String line = this.header.replaceAll("[,;]", separator);
                try {
                    out.write(line);
                    out.newLine();
                    for(contact c : carnet) {
                        if (c.actif) {
                            line = c.toLine(separator, stringEncloser);
                            if (line != null) {
                                System.out.println(String.format("%4d", c.getId())+": "+line);
                                out.write(line);
                                out.newLine();
                            } else {
                                System.out.println(String.format("%4d", c.getId())+""+c.getNom()+" vide");
                                c.actif = false;
                            }
                        } else {
                            System.out.println("["+String.format("%4d", c.getId())+": "+line+"]");
                        }
                    }
                    out.close();
                }
                catch (IOException e) {
                    System.err.println("Trying to read file " + this.input);
                    e.printStackTrace();
                    return false;
                }
            }
        } catch (FileNotFoundException e) {
            System.err.println("Trying to open file " + this.input);
            e.printStackTrace();
            return false;
        } catch (IOException e) {
            System.err.println("Trying to open file " + this.input);
            e.printStackTrace();
            return false;
        }
        return result;
    }

    /**
     * @param input file containing contact list
     */
    public void setFile(File input) {
        this.input = input;
    }

    /**
     * @return file containing contact list
     */
    public File getFile() {
        return input;
    }

    public void deduplicate() {
        //TODO doublons emails et probablement téléphones
        for(contact c : carnet) {
            if (c.actif && c.getId()<carnet.size()-1) {
                System.out.print("Contact "+c.getId()+" = "+c.getNom());
                Boolean f = false;
                for(contact d : carnet.subList(c.getId()+1, carnet.size())) {
                    if (d.actif) {
                        if (c.equals(d)) {
                            System.out.println(" merged with "+d.getId()+" = "+d.getNom());
                            System.out.println("   >"+String.format("%4d", c.getId())+": "+c.toLine(separator, stringEncloser));
                            System.out.println("   +"+String.format("%4d", d.getId())+": "+d.toLine(separator, stringEncloser));
                            c.merge(d);
                            System.out.println("   ="+String.format("%4d", c.getId())+": "+c.toLine(separator, stringEncloser));
                            d.actif = false;
                            f = true;
                        }
                    }
                }
                if (!f) {
                    System.out.println(" unique");
                    System.out.println("   >"+String.format("%4d", c.getId())+": "+c.toLine(separator, stringEncloser));
                }
            }
        }
        int nbTelephones = 0;
        int nbEmails = 0;
        for(contact c : carnet) {
            for(Map.Entry<String,typeTelephone> e : c.getTelephones().entrySet()) {
                if (c.actif) {
                    numeroTelephone t = new numeroTelephone(c.getNom(), e.getValue(), c.getId());
                    if (!telephones.containsKey(e.getKey()))
                        telephones.put(e.getKey(), t);
                } else {
                    numeroTelephone n = telephones.get(e.getKey());
                    if (n==null) {
                        System.out.println("        "+e.getValue().toString()+" "+ e.getKey()+" pour "+c.getNom()+"/"+c.getId()+"perdu.");
/*                    } else {
                        System.out.println("        "+e.getValue().toString()+" "+ e.getKey()+" pour "+c.getNom()+"/"+c.getId()+" mis dans "+n.nom+"/"+n.id);*/
                    }
                }
                nbTelephones += 1;
            }
            c.razTelephones();
            for(Map.Entry<String,String> e : c.getEmails().entrySet()) {
                if (c.actif) {
                    adresseMail a = new adresseMail(c.getNom(), e.getValue(), c.getId());
                    if (!emails.containsKey(e.getKey()))
                        emails.put(e.getKey(), a);
                } else {
                    adresseMail n = emails.get(e.getKey());
                    if (n==null) {
                        System.out.println("        "+e.getValue().toString()+" "+ e.getKey()+" pour "+c.getNom()+"/"+c.getId()+"perdu.");
/*                    } else {
                        System.out.println("        "+e.getValue().toString()+" "+ e.getKey()+" pour "+c.getNom()+"/"+c.getId()+" mis dans "+n.nom+"/"+n.id);*/
                    }
                }
                nbEmails += 1;
            }
            c.razEmails();
        }
        System.out.print(nbTelephones+" téléphones, "+nbEmails+" emails -> ");
        System.out.println(telephones.size()+" téléphones, "+emails.size()+" emails.");
        System.out.print(carnet.size() + " contacts -> ");
        ArrayList r = new ArrayList();
        for(contact c : carnet) {
            if (!c.actif)
                r.add(c);
        }
        carnet.removeAll(r);
        System.out.println(carnet.size() + " contacts");
    }

    public void setCarnet(ArrayList<contact> carnet) {
        this.carnet = carnet;
    }

    public ArrayList<contact> getCarnet() {
        return carnet;
    }

    public void setStringEncloser(String stringEncloser) {
        this.stringEncloser = stringEncloser;
    }

    public String getStringEncloser() {
        return stringEncloser;
    }

    public void setSeparator(String separator) {
        this.separator = separator;
    }

    public String getSeparator() {
        return separator;
    }

    private ArrayList<String> split(String line,String separator, String stringEncloser) {
        ArrayList<String> result = new ArrayList<String>();
        char[] texte = line.toCharArray();
        
        int iStartToken=-1;
        int iEndToken=-1;
        for(int i=0;i < texte.length;i++) {
            if (texte[i]==stringEncloser.charAt(0)) {
                if (iStartToken==-1) iStartToken=i+1;
                else
                    if (i<texte.length-1 && texte[i+1]==stringEncloser.charAt(0))
                        i=i+2;
                    else
                        if (i<texte.length-1 && texte[i+1]==separator.charAt(0))
                            iEndToken=i;
            } else if (texte[i]==separator.charAt(0)) {
                if (iStartToken != -1 && iEndToken == -1){
                    texte[i]=' ';
                } else {
                    if (iStartToken==iEndToken)
                        result.add("");
                    else
                        result.add(String.copyValueOf(texte, iStartToken,iEndToken-iStartToken));
                    iStartToken=-1;
                    iEndToken=-1;
                }
            }
        }
    return result;
    }
}
